﻿//
// error.hpp
// ~~~~~~~~
//

#ifndef YUTOPP_ERROR_HPP
#define YUTOPP_ERROR_HPP

#include <string>
#include <boost/exception/all.hpp>

namespace webapp
{
	namespace error
	{
		enum error_code
		{
			ok						= 0,	// エラーではない。
			http_status,
			network,
			critical,						// 深刻なエラー、ってことになってる。

			unauthorized			= 401,	// 
			forbidden				= 403,
			unknown,
			not_acceptable			= 406,
			too_long				= 413,
			range_unacceptable		= 416,
			rate_limited			= 420,	// イカんでしょ！
			server_internal_error	= 500,
			service_overloaded		= 503
		};


		// エラーの内容を示す。
		//	- codeの内容による状態
		//		ok			: 異常なし。http_status_とmessage_に何が入っているかは不明。
		//		http_status	: HTTPのレスポンスコードが200番台で無かった。message_に何が入っているかは不明。
		//		critical	: 深刻なエラー。http_status_code_に何が入っているかは不明。
		// ok < http_status < network < critical の順でエラー情報は上書きされる。
		class value
		{
		public:
			typedef error_code code_type;
			typedef const char* message_type;
			typedef int status_type;

			value()
				: code_( ok ), message_( "" ), status_( 0 )
			{}

			value( const value& rhs )
				: code_( rhs.code_ ), message_( rhs.message_ ), status_( rhs.status_ )
			{}

			explicit value( error_code code )
				: code_( code ), message_( "" ), status_( 0 )
			{}

			value( error_code code, message_type message )
				: code_( code ), message_( message ), status_( 0 )
			{}

			value( error_code code, status_type status )
				: code_( code ), message_( "" ), status_( status )
			{}

			value( error_code code, message_type message, status_type status )
				: code_( code ), message_( message ), status_( status )
			{}

			error_code get_code() const { return code_; }
			message_type get_message() const { return message_; }
			int get_status() const { return status_; }

			value operator|( const value& rhs ) const
			{
				if ( rhs.get_code() > code_ )
					return rhs;

				return *this;
			}

			value& operator|=( const value& rhs )
			{
				if ( &rhs != this )
					*this = *this | rhs;

				return *this;
			}

			operator bool() const
			{
				return code_ != ok;
			}

		private:
			error_code code_;
			message_type message_;
			status_type status_;
		};


		typedef boost::error_info<struct tag_errno, value::code_type>		code_info;
		typedef boost::error_info<struct tag_errmsg, value::message_type>	message_info;
		typedef boost::error_info<struct tag_errno, value::status_type>		status_info;

		struct exception
			: public boost::exception
		{
			operator value() const
			{
				//エラーコードは必須
				if ( boost::get_error_info<code_info>( *this ) )
					return value( error::critical, "exception has invalid pointer." );

				return value(
					*boost::get_error_info<code_info>( *this ),
					boost::get_error_info<message_info>( *this ) ? *boost::get_error_info<message_info>( *this ) : "",
					boost::get_error_info<status_info>( *this ) ? *boost::get_error_info<status_info>( *this ) : 0
					);
			}
		};

		namespace detail
		{
			void inline throw_exception( const error::value& e )
			{
				throw error::exception()
					<< error::code_info( e.get_code() )
					<< error::message_info( e.get_message() )
					<< error::status_info( e.get_status() );
			}
		}
	} // - error
} // - webapp

#endif /*YUTOPP_ERROR_HPP*/